package com.abpa.util.unidata.resources;

import com.abpa.util.unidata.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * This resource provides access to a XSD that describes the response to a
 * LIST query.
 * @author Matthew Sowders
 */
@Path("{account}/schema/{file}")
public class SchemaResource implements ApplicationContextAware {
    private static final String USER_ROLE = "UNIDATA_REST_USER";

    // The unidata session to connect to
    private Session session;
    // The file that is being queried
    private String filename;
    @Resource
    private ApplicationContext appContext;
    @Context
    private UriInfo context;
    private CommandBuilder builder;
    private CacheManager cacheManager;

    /**
     * This resource provides access to a XSD that describes the response to a
     * LIST query.
     * @param account The name of the Session bean for the session
     * @param file The file that is being queried
     * @param fields The fields that are included in the query
     * @return a HTTP response
     */
    @GET
    @Produces("application/xml")
    public Response getXml(
            @Context SecurityContext sc,
            @DefaultValue("")
            @PathParam("account") String account,
            @DefaultValue("")
            @PathParam("file") String file,
            @QueryParam("fields") @DefaultValue("") String fields) {
        Logger.getLogger(SchemaResource.class.getName()).log(Level.INFO, "GET request", context.getRequestUri().toString());
        Response response;
        Cache cache = cacheManager.getCache(getClass().getName());
        if(!sc.isUserInRole(USER_ROLE)){
            throw new WebApplicationException(Response.Status.FORBIDDEN);
        }
        if (file.equals("") || account.equals("")) {
            return Response.noContent().build();
        }
        if (cache.isKeyInCache(context.getRequestUri())) {
            Element cachedResponse = cache.get(context.getRequestUri());
            if (cachedResponse != null && cachedResponse.getObjectValue() instanceof Response) {
                response = (Response) cachedResponse.getObjectValue();
            } else {
                response = Response.serverError().build();
                Logger.getLogger(SchemaResource.class.getName()).log(Level.SEVERE, "The uri:" + context.getRequestUri().toString() + " exists in cache but the value is not an instance of response or it is null.");
            }
        } else {
            setSession(account);
            setFilename(file);
            Command cmd = builder.requireFields(fields.split("\\+")).list(file).schemaOnly().toXmlElements().build();
            cmd.execute(getSession());
            response = Response.ok(cmd.getResponse()).build();
            cache.put(new Element(context.getRequestUri(), response));
        }
        return response;
    }

    /**
     * @return the session
     */
    public Session getSession() {
        return session;
    }

    /**
     * @param account The name of the Session bean
     */
    public void setSession(String account) {
        session = (Session) appContext.getBean(account);
    }

    /**
     * @return the filename
     */
    public String getFilename() {
        return filename;
    }

    /**
     * @param filename the filename to set
     */
    public void setFilename(String filename) {
        this.filename = filename;
    }

    /**
     * Sets the applicationContext. This is needed to get the Session bean.
     * @param appContext
     * @throws BeansException
     */
    public void setApplicationContext(ApplicationContext appContext) throws BeansException {
        this.appContext = appContext;
    }

    /**
     * @return the builder
     */
    public CommandBuilder getBuilder() {
        return builder;
    }

    /**
     * @param builder the builder to set
     */
    public void setBuilder(CommandBuilder builder) {
        this.builder = builder;
    }

    /**
     * @return the cacheManager
     */
    public CacheManager getCacheManager() {
        return cacheManager;
    }

    /**
     * @param cacheManager the cacheManager to set
     */
    public void setCacheManager(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }
}
